package com.github.niefy.modules.third.filter;

import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONUtil;
import com.github.niefy.common.annotation.AccessLimit;
import com.github.niefy.common.exception.ErrorMessage;
import com.github.niefy.common.utils.EhCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;

/**
 * @author : [86188]
 * @description : 接口防刷拦截器
 * @createTime : [2023/5/31 17:16]
 * @updateUser : [86188]
 * @updateTime : [2023/5/31 17:16]
 */
@Slf4j
@Component
public class AccessLimitInterceptor implements HandlerInterceptor {


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
        //1. 判断请求是否属于方法的请求
        if (handler instanceof HandlerMethod) {
        //2. 取出当前方法的对象
            HandlerMethod methodHandler = (HandlerMethod) handler;
        //3. 获取方法中的注解,看是否有该注解
            AccessLimit accessLimit = methodHandler.getMethodAnnotation(AccessLimit.class);
            //3.1 : 不包含此注解,则不进行操作
            if (accessLimit != null) {
            //3.2 ： 判断请求是否受限制
                if (isLimit(request, accessLimit)) {
                    var resObj = ErrorMessage.messageToR("A0507");
                    ServletUtil.write(response, JSONUtil.toJsonStr(resObj), ContentType.JSON.getValue());
                    return false;
                }
            }
        }
        return true;
    }

    //判断请求是否受限
    public boolean isLimit(HttpServletRequest request, AccessLimit accessLimit) {
        // 缓存key,openid + ServletPath
        String limitKey = request.getAttribute("openid") + request.getServletPath();
        // 从缓存中获取，当前这个请求访问了几次
        Integer count = EhCacheUtils.get(limitKey, "indefiniteLiveTimeCache");
        if (count == null) {
            //初始 次数
            EhCacheUtils.putIndefLiveTimeElement(limitKey, 1, accessLimit.seconds());
            log.debug("写入缓存");
        } else {
            if (count >= accessLimit.maxCount()) {
                return true;
            }
            // 次数自增
            EhCacheUtils.putIndefLiveTimeElement(limitKey, ++count, accessLimit.seconds());
        }
        return false;
    }
}
